#include "QSFMLScreen.h"

#include "SFML/Audio.hpp"
#include "SFML/Graphics.hpp"


#include "spriteref.h"
#include "ImageManager.h"
#include "soundmanager.h"
#include <qpixmap.h>
#include <qstring.h>

#include <qwidget.h>
#include <qpoint.h>
#include <qsize.h>
#include <QtGui>

#include <qdebug.h>
#include "exceptions.h"

QSFMLScreen::QSFMLScreen(QWidget* parent, const QPoint& position, const QSize& size, const QString mapOugames, bool mapOugame)
	: QSFMLCanvas(parent, position, size), m_parent(parent), m_playerTeam(PLAYER_TEAM, "Nom equipe choisi par le joueur"), m_animating(false)
{
	SetFramerateLimit (60);
	setMouseTracking(true);
	m_possibleMoveSprite.Resize(32, 32);
	m_possibleMoveSprite.SetColor(sf::Color(0, 0, 255, 127));
	m_pathShape = sf::Shape::Circle(sf::Vector2f(0,0), 6, sf::Color(0, 127, 0, 127));
        m_selectShape = sf::Shape::Rectangle(0,0,32,32, sf::Color::Red);

	m_tileset = new Tileset("tileset.png",
			"tileset.props",
			"Tileset test");
	//m_map = new Map(map, *m_tileset, "Map test");

	if (mapOugame == 0) {

                QString savePath;
		for (int i = 0; mapOugames[i] != '.'; i++) {
                        savePath += mapOugames[i];
		}
                savePath += ".game";

                Unit* heroes[predefinedHeroesNumber];
                for(quint8 i = 0 ; i < predefinedHeroesNumber ; i++)
                {
                    heroes[i] = new Unit(0, UnitFactory::getInstance().getHeroProperties(i));
                    heroes[i]->setRemainingMoves(heroes[i]->getProperties().movement);
                    m_playerTeam.append(heroes[i]);
                }
                m_gameMap = new GameMap(mapOugames, *m_tileset, m_playerTeam, savePath,0);

                for(quint8 i = 0 ; i < predefinedHeroesNumber ; i++)
                {
                        delete heroes[i];
                }
		m_map = m_gameMap->getMap();
		m_selectedUnit = m_gameMap->getUnits().first();
	}
	else {
                m_gameMap = new GameMap("tmp.map", *m_tileset, m_playerTeam, mapOugames,1);
		m_map = m_gameMap->getMap();
		m_selectedUnit = m_gameMap->getUnits().first();
	}

        if(m_battleMusic.OpenFromFile("sounds/battle.ogg"))
        {
            m_battleMusic.Play();
        }
        else
        {
            throw EX_FILE_NOT_FOUND("sounds/battle.ogg");
        }
}

QSFMLScreen::~QSFMLScreen()
{
        m_battleMusic.Stop();
        m_gameOverSound.Stop();
	delete m_tileset;
	delete m_gameMap;
}

bool QSFMLScreen::isAnimating() const
{
	return m_animating;
}

void QSFMLScreen::OnInit()
{
}

void QSFMLScreen::mousePressEvent(QMouseEvent* e)
{

    if(!isAnimating() && !m_selectedUnit->isIAControlled())
	{
        bool switchUnit = false;
		int x = e->pos().x() / 32;
		int y = e->pos().y() / 32;
        if (x == m_selectedUnit->getX() && y == m_selectedUnit->getY())
		{
			m_activePath.clear();
                        switchUnit = true;
		}
        else if((x != m_selectedUnit->getX() || y != m_selectedUnit->getY()) && !m_selectedUnit->pathTo(x, y).isEmpty())
		{
			m_selectedUnit->moveTo(x,y);
			m_animating = true;
			m_activePath.clear();
		}
		else if(m_gameMap->containsUnit(x,y) && m_selectedUnit->canAttack(x,y))
		{
			Unit* target = m_gameMap->getUnit(x,y);
			m_selectedUnit->attack(target);

            if (m_selectedUnit->getRemainingMoves() == 0)
			{
                                switchUnit = true;
				m_activePath.clear();
			}
		}

        if(switchUnit)
        {
            m_selectedUnit = m_gameMap->getNextUnit();
            if(m_selectedUnit->isIAControlled())
            {
                m_animating = true;
            }
        }
	}
}

void QSFMLScreen::mouseMoveEvent(QMouseEvent* e)
{
	QCursor cursor;
        if ((0 <= e->pos().x() && e->pos().x() < this->width()) && (0 <= e->pos().y() && e->pos().y() < this->height()))
        {
            if(!isAnimating())
            {

                    int x = e->pos().x() / 32;
                    int y = e->pos().y() / 32;

                    const QList<QPoint> path = m_selectedUnit->pathTo(x, y);
                    if(!path.isEmpty() && (x != m_selectedUnit->getX() || y != m_selectedUnit->getY()))
                    {
                            cursor = QCursor(ImageManager::getInstance().getPixmap("img/icons/cursor_move.png"), 0, 0);
                            m_activePath = path;
                    }
                    else if(m_gameMap->containsUnit(x,y) && m_selectedUnit->canAttack(x,y))
                    {
                            cursor = QCursor(ImageManager::getInstance().getPixmap("img/icons/cursor_attack.png"), 0, 0);
                            m_activePath.clear();
                    }
                    else
                    {
                            cursor = QCursor(Qt::ArrowCursor);
                            m_activePath.clear();
                    }

            }
            else
            {
                    cursor = QCursor(Qt::ArrowCursor);
            }

            setCursor(cursor);
            QApplication::setOverrideCursor(cursor);
    }
}


void QSFMLScreen::OnUpdate()
{
    //Clearing screen
    Clear(sf::Color(128, 128, 128));


    //Drawing the tiles map
    for(quint8 j = 0 ; j < m_map->getHeight() ; j++)
    {
        for(quint8 i = 0 ; i < m_map->getWidth() ; i++)
        {
            m_tileSprite = m_map->getTile(i, j).getSpriteRef();
            m_tileSprite.SetPosition(i*32, j*32);
            Draw(m_tileSprite);
        }
    }

    //Drawing the units
    const QList<Unit*>& units = m_gameMap->getUnits();
    bool animate = false;
    for(quint8 i = 0 ; i < units.size() ; ++i)
    {
        if(isAnimating())
        {
            if(units.at(i)->animate())
            {
                animate = true;
            }
        }
        else if (m_selectedUnit == units.at(i))
        {
            m_selectShape.SetPosition(units.at(i)->getX() * 32, units.at(i)->getY() * 32);
            Draw(m_selectShape);
        }

        Draw(units.at(i)->getSpriteRef());

        if(!isAnimating())
        {
            //Draws the units' health
            qint32 health = units.at(i)->getProperties().health;
            qint32 maxHealth = units.at(i)->getProperties().maxHealth;
            QString healthText(QString::number(health));
            healthText += "/";
            healthText += QString::number(maxHealth);
            sf::String drawHealth(healthText.toStdString(), sf::Font::GetDefaultFont(), 12.f);
            drawHealth.SetPosition(units.at(i)->getX() * 32, (units.at(i)->getY()) * 32 + 16);
            qreal healthPercent = (qreal)health / maxHealth;
            drawHealth.SetColor(sf::Color(255*(1-healthPercent), 255*(healthPercent), 0));
            drawHealth.SetStyle(sf::String::Bold);
            Draw(drawHealth);
        }
    }
    m_animating = animate;

    if(m_gameMap->gameIsOver())
    {
        //Drawing "win/lose"
        sf::Sprite SpriteEnd;
        m_battleMusic.Stop();
        if(m_gameMap->getTeamPerdante() == PLAYER_TEAM)
        {
            SpriteEnd.SetImage(ImageManager::getInstance().getImage("img/bg/lose.png"));
            //m_gameOverSound.SetBuffer(SoundManager::getInstance().getSoundBuffer("sounds/lose.mp3"));
            Draw(SpriteEnd);
        }
        else
        {
            SpriteEnd.SetImage(ImageManager::getInstance().getImage("img/bg/win.png"));
            //m_gameOverSound.SetBuffer(SoundManager::getInstance().getSoundBuffer("sounds/win.mp3"));
            Draw(SpriteEnd);
        }
        //m_gameOverSound.Play();

    }
    if(!isAnimating())
    {
        //Drawing available moves
        if(!m_selectedUnit->isIAControlled())
        {
            const QList<QPoint> possibleMoves = m_selectedUnit->availableDestinations();
            for(qint32 i = 0 ; i < possibleMoves.size() ; i++)
            {
                m_possibleMoveSprite.SetPosition(possibleMoves.at(i).x() * 32, possibleMoves.at(i).y() * 32);
                Draw(m_possibleMoveSprite);
            }
        }

        //Drawing the current path if it exists
        if(!m_activePath.isEmpty())
        {
            for(qint32 i = 0 ; i < m_activePath.size() ; i++)
            {
                m_pathShape.SetPosition(m_activePath.at(i).x() * 32 + 16, m_activePath.at(i).y() * 32 + 16);
                Draw(m_pathShape);
            }
        }
        if((m_selectedUnit->isIAControlled() && !m_selectedUnit->getRemainingAction())
            || (!m_selectedUnit->isIAControlled() && !m_selectedUnit->isMovePossible() && m_selectedUnit->canAttackSomeone().isEmpty()))
            {
            if(m_selectedUnit->isIAControlled())
            {
                m_selectedUnit->attack(0);
            }
            m_selectedUnit = m_gameMap->getNextUnit();
            if(m_selectedUnit->isIAControlled())
            {
                m_animating = true;
            }
        }
    }
}
